package com.googlecode.gamedroid;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;

import com.googlecode.gamedroid.gamepad.GamePad;
import com.googlecode.gamedroid.gamepad.GamePadExtended;
import com.googlecode.gamedroid.gamepad.GamePadStandard;
import com.googlecode.gamedroid.sockethelper.DeviceList;

public class Selector extends Activity
{
	private static final int DEFAULT_PORT = 56365; // TODO move to preferences
	private static final Class<?>[] GAMEPADS =
	{
		GamePadStandard.class,
		GamePadExtended.class
	};
	private static String MY_UUID = "00001101-0000-1000-8000-00805F9B34FB";
	private static final int REQUEST_ENABLE_BLUETOOTH = 1;
	private static final int REQUEST_SELECT_DEVICE = 2;
	
	private GamePadAdapter adapter;
	private BluetoothAdapter bluetooth;
	private Button btnStart;
	private ListView lvGamepads;
	private SharedPreferences mPreferences;
	private TextView tvHostType, tvHostName, tvGamePad, tvGamePadHeader;
	
	private boolean checkBluetooth()
	{
		if(bluetooth == null)
			return false;
		
		if(bluetooth.isEnabled())
			return true;
		
		Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
		startActivityForResult(intent, REQUEST_ENABLE_BLUETOOTH);
		return false;
	}
	
	@SuppressLint("DefaultLocale")
	private void onDeviceChanged()
	{
		if(!mPreferences.contains("type"))
		{
			tvHostName.setVisibility(View.GONE);
			tvHostType.setText(R.string.msg_no_device_selected);
			btnStart.setEnabled(false);
			return;
		}
		
		btnStart.setEnabled(true);
		tvHostName.setVisibility(View.VISIBLE);
		
		String type = "", name = "";
		if(mPreferences.getString("type", "").equals("bluetooth"))
		{
			type = getString(R.string.header_bluetooth);
			name = String.format("%s [%s]",
				mPreferences.getString("bluetooth.name", ""),
				mPreferences.getString("bluetooth.device", ""));
		}
		else if(mPreferences.getString("type", "").equals("network"))
		{
			type = getString(R.string.header_network);
			name = String.format("%s:%d",
				mPreferences.getString("network.host", ""),
				mPreferences.getInt("network.port", DEFAULT_PORT));
		}
		
		tvHostType.setText(type);
		tvHostName.setText(name);
	}
	
	private void onDeviceSelected(Intent data)
	{
		if(data.getStringExtra("type").equals("cancel"))
			return;
		
		Editor editor = mPreferences.edit();
		
		if(data.getStringExtra("type").equals("network"))
		{
			editor.putString("type", "network");
			editor.putString("network.host", data.getStringExtra("network.host"));
			editor.putInt("network.port", data.getIntExtra("network.port", DEFAULT_PORT));
		}
		else if(data.getStringExtra("type").equals("bluetooth"))
		{
			editor.putString("type", "bluetooth");
			
			String address = data.getStringExtra("bluetooth.device");
			BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
			BluetoothDevice device = adapter.getRemoteDevice(address);
			
			editor.putString("bluetooth.device", address);
			editor.putString("bluetooth.name", device.getName());
		}
		editor.commit();
		
		onDeviceChanged();
	}
	
	@SuppressWarnings("unchecked")
	private void onGamePadChanged()
	{
		String name = mPreferences.getString("gamepad", GAMEPADS[0].getName());
		
		Class<? extends GamePad> gamepad = null;
		try
		{
			gamepad = (Class<? extends GamePad>) Class.forName(name);
		}
		catch(ClassNotFoundException e)
		{
			try
			{
				gamepad = (Class<? extends GamePad>) Class.forName(GAMEPADS[0].getName());
			}
			catch(ClassNotFoundException e1)
			{
				e1.printStackTrace();
				finish();
				return;
			}
		}
		
		adapter.setActiveItem(gamepad);
		
		tvGamePad.setText(GamePad.getDescription(gamepad));
		tvGamePadHeader.setCompoundDrawablesWithIntrinsicBounds(
			null,
			null,
			getResources().getDrawable(GamePad.getIcon(gamepad)),
			null);
	}
	
	private void onGamePadSelected(int position)
	{
		Class<? extends GamePad> item = adapter.getItem(position);
		
		Editor editor = mPreferences.edit();
		editor.putString("gamepad", item.getName());
		editor.commit();
		
		onGamePadChanged();
	}
	
	private void startConnection()
	{
		// TODO warn when WiFi selected but on mobile data connection
		
		Class<?> klass = adapter.getActiveItem();
		Intent intent = new Intent(this, klass);
		
		if(!mPreferences.contains("type"))
			return;
		intent.putExtra("type", mPreferences.getString("type", ""));
		
		if(mPreferences.getString("type", "").equals("bluetooth"))
		{
			if(!mPreferences.contains("bluetooth.device"))
				return;
			
			if(!checkBluetooth())
				return;
			
			intent.putExtra("bluetooth.device", mPreferences.getString("bluetooth.device", ""));
			intent.putExtra("bluetooth.uuid", MY_UUID);
		}
		else if(mPreferences.getString("type", "").equals("network"))
		{
			if(!(mPreferences.contains("network.host") && mPreferences.contains("network.port")))
				return;
			intent.putExtra("network.host", mPreferences.getString("network.host", ""));
			intent.putExtra("network.port", mPreferences.getInt("network.port", DEFAULT_PORT));
		}
		
		startActivity(intent);
	}
	
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data)
	{
		switch(requestCode)
		{
			case REQUEST_ENABLE_BLUETOOTH:
				if(resultCode == RESULT_OK)
					startConnection();
				break;
			
			case REQUEST_SELECT_DEVICE:
				if(resultCode == RESULT_OK)
					onDeviceSelected(data);
				break;
			
			default:
				super.onActivityResult(requestCode, resultCode, data);
		}
	}
	
	@SuppressWarnings("unchecked")
	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		
		adapter = new GamePadAdapter(this);
		for(int i = 0; i < GAMEPADS.length; i++)
			adapter.add((Class<? extends GamePad>) GAMEPADS[i]);
		
		bluetooth = BluetoothAdapter.getDefaultAdapter();
		
		setContentView(R.layout.activity_selector);
		
		lvGamepads = (ListView) findViewById(R.id.lv_gamepads);
		lvGamepads.setAdapter(adapter);
		lvGamepads.setOnItemClickListener(new AdapterView.OnItemClickListener()
		{
			@Override
			public void onItemClick(AdapterView<?> parent, View view, int position, long id)
			{
				onGamePadSelected(position);
			}
		});
		
		btnStart = (Button) findViewById(R.id.btn_start);
		
		tvHostType = (TextView) findViewById(R.id.tv_host_type);
		tvHostName = (TextView) findViewById(R.id.tv_host_name);
		tvGamePad = (TextView) findViewById(R.id.tv_gamepad);
		tvGamePadHeader = (TextView) findViewById(R.id.tv_gamepad_header);
		
		PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
		mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
		
		onGamePadChanged();
		onDeviceChanged();
	}
	
	@Override
	protected void onStart()
	{
		super.onStart();
		
		if(mPreferences.getBoolean(Preferences.PREF_ROTATE180, false))
			setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
		else
			setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
	
	public void onChooseClick(MenuItem item)
	{
		Intent intent = new Intent(this, DeviceList.class);
		
		String host = mPreferences.getString("network.host", "");
		intent.putExtra("default.host", host);
		int port = mPreferences.getInt("network.port", DEFAULT_PORT);
		intent.putExtra("default.port", port);
		intent.putExtra("is_cancelable", true);
		startActivityForResult(intent, REQUEST_SELECT_DEVICE);
	}
	
	public boolean onCreateOptionsMenu(Menu menu)
	{
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.activity_selector, menu);
		return true;
	}
	
	public void onPreferencesClick(MenuItem item)
	{
		Intent intent = new Intent(this, Preferences.class);
		startActivity(intent);
	}
	
	public void onStartClick(View v)
	{
		startConnection();
	}
}
